#pragma once

//auto_ptr
//unique_ptr
//shared_ptr
//weak_ptr



namespace ztb
{
	template<class T>
	class auto_ptr
	{
	public:
		auto_ptr(T* _a)
			:_ptr(_a)
		{
			cout << "auto_ptr()" << endl;
		}

		~auto_ptr()
		{
			cout << "delete :" << _ptr << endl;
			delete _ptr;
		}

		T* operator->()
		{
			return _ptr;//this
		}

		T& operator*()
		{
			return *_ptr;
		}

		auto_ptr(auto_ptr<T>& tmp)
			:_ptr(tmp._ptr)
		{
			cout << "delete :" << tmp._ptr << endl;
			tmp._ptr =  nullptr ;
		}

	private:
		T* _ptr;

	};



	template<class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr)
			:_ptr(ptr)
			,_prcunt(new int(1))
		{}

		~shared_ptr()
		{
			if (--(*_prcunt) == 0)
			{
				cout << "delete :" << _ptr << " delete :" << _prcunt << endl;
				delete _ptr;
				delete _prcunt;
			}
		}

		T* operator->()const
		{
			return _ptr;
		}

		T& operator*()const
		{
			
				return *_ptr;
		}

		int get_prcunt()const
		{
			return *_prcunt;
		}

		T* get_ptr()const
		{
			return _ptr;
		}

		shared_ptr(shared_ptr<T>& ap)
			:_ptr(ap._ptr)
			,_prcunt(ap._prcunt)
		{
			++(*_prcunt);
		}

		shared_ptr<T> operator=(shared_ptr<T>& ap)
		{
			if (_ptr == ap._ptr)
			{
				return *this;
			}

			if (--(*_prcunt) == 0)
			{
				cout << "delete :" << _ptr << " delete :" << _prcunt << endl;
				delete _ptr;
				delete _prcunt;
			}

			_ptr = ap._ptr;
			_prcunt = ap._prcunt;

			++(*_prcunt);
			return *this;
		}

	private:
		T* _ptr;
		int* _prcunt;
	};
}
